package com.sooth.micro.camunda.converter.processing.task;

import cn.hutool.core.collection.CollUtil;
import com.sooth.common.json.utils.JsonUtils;
import com.sooth.micro.camunda.converter.bean.BaseDefinition;
import com.sooth.micro.camunda.converter.bean.extension.Candidate;
import com.sooth.micro.camunda.converter.bean.extension.ExtBpmConstant;
import com.sooth.micro.camunda.converter.bean.listener.TaskListener;
import com.sooth.micro.camunda.converter.bean.task.UserTaskDefinition;
import com.sooth.micro.camunda.converter.processing.BpmnElementProcessor;
import org.camunda.bpm.model.bpmn.builder.AbstractFlowNodeBuilder;
import org.camunda.bpm.model.bpmn.builder.UserTaskBuilder;
import org.camunda.bpm.model.bpmn.instance.ExtensionElements;
import org.camunda.bpm.model.bpmn.instance.UserTask;
import org.camunda.bpm.model.bpmn.instance.camunda.CamundaProperty;

import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class UserTaskProcessor
        implements BpmnElementProcessor<UserTaskDefinition, AbstractFlowNodeBuilder> {

    private static final List<String> EVENT_TYPES =
            Arrays.asList("create", "assignment", "complete", "delete", "update");

    @Override
    public String onComplete(AbstractFlowNodeBuilder flowNodeBuilder, UserTaskDefinition flowNode)
            throws InvocationTargetException, IllegalAccessException {
        String id = flowNode.getId();
        String nodeType = flowNode.getNodeType();
        String nodeName = flowNode.getNodeName();
//        String assignee = flowNode.getAssignee();
//        String candidateUsers = flowNode.getCandidateUsers();
//        String candidateGroups = flowNode.getCandidateGroups();
        List<Candidate> candidateList = flowNode.getCandidateList();
        String candidateGroups = candidateList.stream().map(Candidate::getId).collect(Collectors.joining(","));
        UserTask userTask = (UserTask) createInstance(flowNodeBuilder, nodeType);
        userTask.setId(id);
        userTask.setName(nodeName);
        ExtensionElements extensionElements = userTask.getModelInstance().newInstance(ExtensionElements.class);
        CamundaProperty camundaProperty = extensionElements.addExtensionElement(CamundaProperty.class);
        camundaProperty.setAttributeValue(ExtBpmConstant.FORM_PERM, JsonUtils.toJsonString(flowNode.getFormPermList()));
        camundaProperty.setAttributeValue(ExtBpmConstant.BUTTON_PERM, JsonUtils.toJsonString(flowNode.getButtonPermList()));
        userTask.setExtensionElements(extensionElements);
        UserTaskBuilder userTaskBuilder = userTask.builder();
        userTaskBuilder.camundaFormKey(String.valueOf(flowNode.getPageId()));
//        if (StringUtils.isNotBlank(assignee)) {
//            userTaskBuilder.camundaAssignee(assignee);
//        }
//
//        if (StringUtils.isNotBlank(candidateUsers)) {
//            userTaskBuilder.camundaCandidateUsers(candidateUsers);
//        }
        userTaskBuilder.camundaCandidateGroups(candidateGroups);

        // create task listener
        createTaskListener(userTaskBuilder, flowNode);

        // create execution listener
        createExecutionListener(userTaskBuilder, flowNode);

        id = userTask.getId();
        // 如果当前任务还有后续任务，则遍历创建后续任务
        BaseDefinition nextNode = flowNode.getNextNode();
        if (Objects.nonNull(nextNode)) {
            return onCreate(moveToNode(flowNodeBuilder, id), nextNode);
        } else {
            return id;
        }
    }

    /**
     * 创建任务监听器
     *
     * @param userTaskBuilder builder
     * @param flowNode        当前节点
     */
    private void createTaskListener(UserTaskBuilder userTaskBuilder, UserTaskDefinition flowNode) {
        final List<TaskListener> listeners = flowNode.getTaskListeners();
        if (CollUtil.isNotEmpty(listeners)) {
            listeners.forEach(
                    listener -> {
                        final String eventType = listener.getEventType();
                        if (!EVENT_TYPES.contains(eventType)) {
                            throw new IllegalArgumentException("Unsupported event of type " + eventType);
                        }

                        if (listener.isClass()) {
                            userTaskBuilder.camundaTaskListenerClass(eventType, listener.getJavaClass());
                        } else if (listener.isDelegateExpression()) {
                            userTaskBuilder.camundaTaskListenerDelegateExpression(
                                    eventType, listener.getDelegateExpression());
                        } else if (listener.isExpression()) {
                            userTaskBuilder.camundaTaskListenerExpression(eventType, listener.getExpression());
                        }
                    });
        }
    }
}
